home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / GLUT-3.7 / LIB / GLE / round_cap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-08-12  |  6.3 KB  |  212 lines

  1. /*
  2.  * MODULE NAME: round_cap.c
  3.  *
  4.  * FUNCTION:
  5.  * This module contains code that draws the round end-cap for round
  6.  * join-style tubing.
  7.  *
  8.  * HISTORY:
  9.  * written by Linas Vepstas August/September 1991
  10.  * split into multiple compile units, Linas, October 1991
  11.  * added normal vectors Linas, October 1991
  12.  */
  13.  
  14.  
  15. #include <malloc.h>
  16. #include <stdlib.h>
  17. #include <math.h>
  18. #include <string.h>    /* for the memcpy() subroutine */
  19. #include <GL/tube.h>
  20. #include "port.h"
  21. #include "gutil.h"
  22. #include "vvector.h"
  23. #include "extrude.h"
  24. #include "tube_gc.h"
  25. #include "intersect.h"
  26. #include "segment.h"
  27.  
  28.  
  29. /* ============================================================ */
  30. /* This routine does what it says: It draws the end-caps for the
  31.  * "round" join style.
  32.  */
  33.  
  34. /* HACK ALERT HACK ALERT HACK ALERT HACK ALERT */
  35. /* This #define should be replaced by some adaptive thingy.
  36.  * the adaptiveness needs to depend on relative angles and diameter of
  37.  * extrusion relative to screen size (in pixels).
  38.  */
  39.  
  40. #define __ROUND_TESS_PIECES 5
  41.  
  42. void draw_round_style_cap_callback (int ncp,
  43.                                   double cap[][3],
  44.                                   float face_color[3],
  45.                                   gleDouble cut[3],
  46.                                   gleDouble bi[3],
  47.                                   double norms[][3],
  48.                                   int frontwards)
  49. {
  50.    double axis[3];
  51.    double xycut[3];
  52.    double theta;
  53.    double *last_contour, *next_contour;
  54.    double *last_norm, *next_norm;
  55.    double *cap_z;
  56.    double *tmp;
  57.    char *malloced_area;
  58.    int i, j, k;
  59.    double m[4][4];
  60.  
  61.    if (face_color != NULL) C3F (face_color);
  62.  
  63.    /* ------------ start setting up rotation matrix ------------- */
  64.    /* if the cut vector is NULL (this should only occur in
  65.     * a degenerate case), then we can't draw anything. return. */
  66.    if (cut == NULL) return;
  67.  
  68.    /* make sure that the cut vector points inwards */
  69.    if (cut[2] > 0.0) {
  70.       VEC_SCALE (cut, -1.0, cut);
  71.    }
  72.  
  73.    /* make sure that the bi vector points outwards */
  74.    if (bi[2] < 0.0) {
  75.       VEC_SCALE (bi, -1.0, bi);
  76.    }
  77.  
  78.    /* determine the axis we are to rotate about to get bi-contour.
  79.     * Note that the axis will always lie in the x-y plane */
  80.    VEC_CROSS_PRODUCT (axis, cut, bi);
  81.  
  82.    /* reverse the cut vector for the back cap -- 
  83.     * need to do this to get angle right */
  84.    if (!frontwards) {
  85.       VEC_SCALE (cut, -1.0, cut);
  86.    }
  87.  
  88.    /* get angle to rotate by -- arccos of dot product of cut with cut
  89.     * projected into the x-y plane */
  90.    xycut [0] = 0.0;
  91.    xycut [1] = 0.0;
  92.    xycut [2] = 1.0;
  93.    VEC_PERP (xycut, cut, xycut);
  94.    VEC_NORMALIZE (xycut);
  95.    VEC_DOT_PRODUCT (theta, xycut, cut);
  96.  
  97.    theta = acos (theta);
  98.  
  99.    /* we'll tesselate round joins into a number of teeny pieces */
  100.    theta /= (double) __ROUND_TESS_PIECES;
  101.  
  102.    /* get the matrix */
  103.    urot_axis_d (m, theta, axis);
  104.  
  105.    /* ------------ done setting up rotation matrix ------------- */
  106.  
  107.    /* This malloc is a fancy version of:
  108.     * last_contour = (double *) malloc (3*ncp*sizeof(double);
  109.     * next_contour = (double *) malloc (3*ncp*sizeof(double);
  110.     */
  111.    malloced_area = malloc ((4*3+1) *ncp*sizeof (double));
  112.    last_contour = (double *) malloced_area;
  113.    next_contour = last_contour +  3*ncp;
  114.    cap_z = next_contour + 3*ncp;
  115.    last_norm = cap_z + ncp;
  116.    next_norm = last_norm + 3*ncp;
  117.  
  118.    /* make first copy of contour */
  119.    if (frontwards) {
  120.       for (j=0; j<ncp; j++) {
  121.          last_contour[3*j] = cap[j][0];
  122.          last_contour[3*j+1] = cap[j][1];
  123.          last_contour[3*j+2] = cap_z[j] = cap[j][2];
  124.       }
  125.  
  126.       if (norms != NULL) {
  127.          for (j=0; j<ncp; j++) {
  128.             VEC_COPY ((&last_norm[3*j]), norms[j]);
  129.          }
  130.       }
  131.    } else {
  132.       /* in order for backfacing polygon removal to work correctly, have
  133.        * to have the sense in which the joins are drawn to be reversed 
  134.        * for the back cap.  This can be done by reversing the order of
  135.        * the contour points.  Normals are a bit trickier, since the 
  136.        * reversal is off-by-one for facet normals as compared to edge 
  137.        * normals. */
  138.       for (j=0; j<ncp; j++) {
  139.          k = ncp - j - 1;
  140.          last_contour[3*k] = cap[j][0];
  141.          last_contour[3*k+1] = cap[j][1];
  142.          last_contour[3*k+2] = cap_z[k] = cap[j][2];
  143.       }
  144.  
  145.       if (norms != NULL) {
  146.          if (__TUBE_DRAW_FACET_NORMALS) {
  147.             for (j=0; j<ncp-1; j++) {
  148.                k = ncp - j - 2;
  149.                VEC_COPY ((&last_norm[3*k]), norms[j]);
  150.             }
  151.          } else {
  152.             for (j=0; j<ncp; j++) {
  153.                k = ncp - j - 1;
  154.                VEC_COPY ((&last_norm[3*k]), norms[j]);
  155.             }
  156.          }
  157.       }
  158.    }
  159.  
  160.    /* &&&&&&&&&&&&&& start drawing cap &&&&&&&&&&&&& */
  161.  
  162.    for (i=0; i<__ROUND_TESS_PIECES; i++) {
  163.       for (j=0; j<ncp; j++) {
  164.          next_contour [3*j+2] -= cap_z[j];
  165.          last_contour [3*j+2] -= cap_z[j];
  166.          MAT_DOT_VEC_3X3 ( (&next_contour[3*j]), m, (&last_contour[3*j]));
  167.          next_contour [3*j+2] += cap_z[j];
  168.          last_contour [3*j+2] += cap_z[j];
  169.       }
  170.  
  171.       if (norms != NULL) {
  172.          for (j=0; j<ncp; j++) {
  173.             MAT_DOT_VEC_3X3 ( (&next_norm[3*j]), m, (&last_norm[3*j]));
  174.          }
  175.       }
  176.  
  177.       /* OK, now render it all */
  178.       if (norms == NULL) {
  179.          draw_segment_plain (ncp, (gleVector *) next_contour, 
  180.                                   (gleVector *) last_contour, 0, 0.0);
  181.       } else
  182.       if (__TUBE_DRAW_FACET_NORMALS) {
  183.          draw_binorm_segment_facet_n (ncp, 
  184.                                (gleVector *) next_contour, 
  185.                                (gleVector *) last_contour,
  186.                                (gleVector *) next_norm, 
  187.                                (gleVector *) last_norm, 0, 0.0);
  188.       } else {
  189.          draw_binorm_segment_edge_n (ncp,
  190.                                (gleVector *) next_contour, 
  191.                                (gleVector *) last_contour,
  192.                                (gleVector *) next_norm, 
  193.                                (gleVector *) last_norm, 0, 0.0);
  194.      }
  195.  
  196.       /* swap contours */
  197.       tmp = next_contour;
  198.       next_contour = last_contour;
  199.       last_contour = tmp;
  200.  
  201.       tmp = next_norm;
  202.       next_norm = last_norm;
  203.       last_norm = tmp;
  204.    }
  205.    /* &&&&&&&&&&&&&& end drawing cap &&&&&&&&&&&&& */
  206.  
  207.    /* Thou shalt not leak memory */
  208.    free (malloced_area);
  209. }
  210.  
  211. /* ==================== END OF FILE =========================== */
  212.